﻿using System;
using System.Net;
using System.Runtime.CompilerServices;

namespace Net.Helper
{
    public static class ByteHelper
    {
        /// <summary>
        /// 转换方法
        /// </summary>
        /// <param name="size">字节值</param>
        /// <returns></returns>
        public static string ToString(double size)
        {
            var units = new string[] { "B", "K", "M", "G", "T", "P" };
            double mod = 1024.0;
            int i = 0;
            while (size >= mod)
            {
                size /= mod;
                i++;
            }
            return Math.Round(size, 2) + units[i];
        }

        public static string ToByteString(this int size) => ToString(size);
        public static string ToByteString(this uint size) => ToString(size);
        public static string ToByteString(this long size) => ToString(size);
        public static string ToByteString(this ulong size) => ToString(size);
        public static string ToByteString(this float size) => ToString(size);
        public static string ToByteString(this double size) => ToString(size);

        /// <summary>
        /// 设置二进制值
        /// </summary>
        /// <param name="data">要修改的数据</param>
        /// <param name="index">索引从1-8</param>
        /// <param name="flag">填二进制的0或1</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void SetBit(ref byte data, int index, bool flag)
        {
            if (flag)
                data |= (byte)(1 << (8 - index));
            else
                data &= (byte)~(1 << (8 - index));
        }

        /// <summary>
        /// 设置二进制值
        /// </summary>
        /// <param name="data">要修改的数据</param>
        /// <param name="index">索引从1-8</param>
        /// <param name="flag">填二进制的0或1</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static byte SetBit(byte data, int index, bool flag)
        {
            SetBit(ref data, index, flag);
            return data;
        }

        /// <summary>
        /// 获取二进制值
        /// </summary>
        /// <param name="data">要获取的数据</param>
        /// <param name="index">索引从1-8</param>
        /// <returns>返回二进制的0或1</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetBit(byte data, int index)
        {
            return ((data >> (8 - index)) & 1) == 1;
        }

        /// <summary>
        /// 设置二进制位
        /// </summary>
        /// <param name="number"></param>
        /// <param name="position"></param>
        /// <param name="set"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int SetBit(this int number, int position, bool set)
        {
            if (set)
                return number | (1 << (31 - position));
            else
                return number & ~(1 << (31 - position));
        }

        /// <summary>
        /// 获取二进制位
        /// </summary>
        /// <param name="number"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetBit(this int number, int position)
        {
            return (number & (1L << (31 - position))) != 0;
        }

        /// <summary>
        /// 设置二进制位
        /// </summary>
        /// <param name="number"></param>
        /// <param name="position"></param>
        /// <param name="set"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static long SetBit(this long number, int position, bool set)
        {
            if (set)
                return number | (1L << (63 - position));
            else
                return number & ~(1L << (63 - position));
        }

        /// <summary>
        /// 获取二进制位
        /// </summary>
        /// <param name="number"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetBit(this long number, int position)
        {
            return (number & (1L << (63 - position))) != 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static long GetRemoteId(this EndPoint endPoint)
        {
            var remotePoint = endPoint as IPEndPoint;
            return (remotePoint.Address.Address & 0xFFFFFFFFL) | (remotePoint.Port & 0xFFFFL) << 32;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static EndPoint AsRemote(this long remoteId)
        {
            return new IPEndPoint(remoteId & 0xFFFFFFFF, (int)((remoteId >> 32) & 0xFFFF));
        }
    }
}